package com.sky.aspect.dish;

import com.sky.annotation.dish.DishParam;
import com.sky.constant.UserConstant;
import com.sky.dto.DishDTO;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.enumeration.OperationType;
import com.sky.exception.ParamErrorException;
import com.sky.mapper.CategoryMapper;
import com.sky.mapper.DishMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

@Aspect
@Component
@Slf4j
public class DishParamAspect {

    @Resource
    private DishMapper dishMapper;

    @Resource
    private CategoryMapper categoryMapper;

    @Pointcut("@annotation(com.sky.annotation.dish.DishParam)")
    public void pointCut() {
    }

    @Before("pointCut()")
    public void doValidate(JoinPoint point) {
        log.info("参数校验开始");
        OperationType operationType = getOperationType(point);
        Object[] args = point.getArgs();
        if (args.length == 0) {
            return;
        }
        DishDTO dish = (DishDTO) args[0];
        if (operationType == OperationType.INSERT) {
            doInsertValidate(dish);
        } else if (operationType == OperationType.UPDATE) {
            doUpdateValidate(dish);
        }
    }

    /**
     * 修改菜品时的参数校验
     * id不能为空
     * 其他的字段若不为空再进行判断
     *
     * @param dish
     */
    private void doUpdateValidate(DishDTO dish) {
        if (Objects.isNull(dish.getId())) {
            throw new ParamErrorException("菜品id不能为空");
        }
        if (Objects.nonNull(dish.getName()) && hasDish(dish.getName())) {
            throw new ParamErrorException("菜品名称已存在");
        }
        if (Objects.nonNull(dish.getCategoryId()) && !hasCategory(dish.getCategoryId())) {
            throw new ParamErrorException("菜品分类不存在");
        }
        if (Objects.nonNull(dish.getStatus()) && !UserConstant.validateStatusLegal(dish.getStatus())) {
            throw new ParamErrorException("菜品状态不合法");
        }

        // 口味校验
        flavorValidate(dish.getFlavors());
    }

    /**
     * 添加菜品时的参数校验
     *
     * @param dish
     */
    private void doInsertValidate(DishDTO dish) {
        if (Objects.isNull(dish.getName()) || dish.getName().isEmpty()) {
            throw new ParamErrorException("菜品名称不能为空");
        }

        if (Objects.isNull(dish.getCategoryId()) || dishMapper.getByCategoryId(dish.getCategoryId()).isEmpty()) {
            throw new ParamErrorException("菜品分类不存在");
        }

        if (Objects.isNull(dish.getPrice()) || dish.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ParamErrorException("菜品价格不能为空且必须大于0");
        }

        if (Objects.isNull(dish.getStatus()) || !UserConstant.validateStatusLegal(dish.getStatus())) {
            throw new ParamErrorException("菜品状态不合法");
        }

        // 口味校验
        flavorValidate(dish.getFlavors());
    }

    /**
     * 口味数据校验
     * @param flavors
     */
    private void flavorValidate(List<DishFlavor> flavors) {
        if (!flavors.isEmpty()) {
            flavors.forEach(flavor -> {
                if (Objects.isNull(flavor.getName())) {
                    throw new ParamErrorException("菜品口味名称不能为空");
                }
                if (Objects.isNull(flavor.getValue())) {
                    throw new ParamErrorException("菜品口味值不能为空");
                }
            });
        }
    }

    /**
     * 验证菜品名称那个是否存在
     * 若存在则返回true，反之则返回false
     * @param dishName
     * @return
     */
    private boolean hasDish(String dishName) {
        Dish dish = new Dish().builder().name(dishName).build();
        if (!dishMapper.conditionalQuery(dish).isEmpty()) {
            return true;
        }
        return false;
    }

    /**
     * 验证分类是否存在
     * 若存在则返回true，反之则返回false
     * @param categoryId
     * @return
     */
    private boolean hasCategory(Long categoryId) {
        if (Objects.nonNull(categoryMapper.getCategoryById(categoryId))) {
            return true;
        }
        return false;
    }

    /**
     * 获取操作类型
     *
     * @param point
     * @return
     */
    private OperationType getOperationType(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        DishParam annotation = signature.getMethod().getAnnotation(DishParam.class);
        return annotation.value();
    }
}
